package com.anrongtec.zcpt.utils;

import android.app.Application;
import android.os.Environment;
import android.util.Log;
import android.util.SparseArray;

import com.anrongtec.zcpt.constant.Dateformater;
import com.anrongtec.zcpt.constant.GlobalExceptionHandler;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 作者：liuhui on 2017/2/12 22:51
 * 邮箱：liu594545591@126.com
 * 描述：LogUtil
 */

public final class LogUtil {

    private static boolean logoff = true;
    private static boolean isPrint = true;
    private static int level = Log.WARN; //
    private static String STORAGE_PATH = Environment
            .getExternalStorageDirectory().getPath();
    private static String saveDirName = "/anrong/log/";
    private static String saveDir;

    // if (BuildConfig.DEBUG && Log.isLoggable("TAG", Log.VERBOSE)) {
    // Log.v("TAG", message);
    // }

    /**
     *
     * @Title: init
     * @Description: logUtil初始化
     * @param level
     *            指定把高于或等于Error的信息保存到sdcard文件，因为最高的error权限是6，也就是说这里指定为大于6，
     *            即使是错误信息也不会写入sdcard里面
     * @param saveDirName
     *            目录名字，任意指定,如果不指定就在/anrong/log/目录下
     * @param logoff
     *            屏蔽打印
     * @return void 返回类型
     * @throws
     */
    public static void init(int level, String saveDirName, boolean logoff) {
        LogUtil.level = level;
        LogUtil.saveDirName = saveDirName;
        LogUtil.logoff = logoff;
    }

    public static void init(int level, String saveDirName, boolean logoff,
                            boolean isPrint) {
        LogUtil.level = level;
        LogUtil.saveDirName = saveDirName;
        LogUtil.logoff = logoff;
        LogUtil.isPrint = isPrint;
    }

    /**
     *
     * @Title: trace
     * @Description: (这里用一句话描述这个方法的作用)
     * @param type
     * @param tag
     * @param msg
     *            设定文件
     * @return void 返回类型
     * @throws
     */
    public static void trace(final int type, String tag, final String msg) {
        if (logoff && type == Log.DEBUG) {
            Log.d(tag, msg);
        }
        switch (type) {
            case Log.VERBOSE:
                Log.v(tag, msg);
                break;
            case Log.INFO:
                Log.i(tag, msg);
                break;
            case Log.WARN:
                Log.w(tag, msg);
                break;
            case Log.ERROR:
                Log.e(tag, msg);
                break;
        }
        // Write to file
        if (isPrint && type >= level) {
            new Thread() {
                public void run() {
                    writeLog(type, msg, true);
                }
            }.start();
        }
    }

    /**
     * Custom Log output style
     *
     * @param type
     *            Log type log的类型（error，warn等等）
     * @param tag
     *            TAG tag:输出标志
     * @param msg
     *            输出日志 Log message
     * @param isContinueWrite
     *            isContinueWrite:默认是true，即是上面没有这个参数的方法，
     *            表示继续在原有文件写入，如果是false则创建一个新的覆盖原来的它。
     */
    public static void trace(final int type, final String tag,
                             final String msg, final boolean isContinueWrite) {
        if (logoff && type == Log.DEBUG) {
            Log.d(tag, msg);
        }
        switch (type) {
            case Log.VERBOSE:
                Log.v(tag, msg);
                break;
            case Log.DEBUG:
                Log.d(tag, msg);
                break;
            case Log.INFO:
                Log.i(tag, msg);
                break;
            case Log.WARN:
                Log.w(tag, msg);
                break;
            case Log.ERROR:
                Log.e(tag, msg);
                break;
        }
        // Write to file
        if (isPrint && type >= level) {
            new Thread() {
                public void run() {
                    writeLog(type, msg, isContinueWrite);
                }
            }.start();
        }
    }

    /**
     * Write log file to the SDcard
     *
     * @param type
     * @param msg
     */
    private static void writeLog(int type, String msg, boolean isContinueWrite) {
        if (!Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            return;
        }
        try {
            SparseArray<String> logMap = new SparseArray<String>();
            logMap.put(Log.VERBOSE, " VERBOSE ");
            logMap.put(Log.DEBUG, " DEBUG ");
            logMap.put(Log.INFO, " INFO ");
            logMap.put(Log.WARN, " WARN ");
            logMap.put(Log.ERROR, " ERROR ");

            final StackTraceElement tag = new Throwable().fillInStackTrace()
                    .getStackTrace()[2];

            msg = new StringBuilder().append("\r\n")
                    .append(getDateformat(Dateformater.SS.getValue()))
                    .append(logMap.get(type)).append(tag.getClassName())
                    .append(" - ").append(tag.getMethodName()).append("(): ")
                    .append(msg).toString();

            final String fileName = new StringBuffer().append("log-")
                    .append(getDateformat(Dateformater.DD.getValue()))
                    .append(".log").toString();

            saveDir = STORAGE_PATH + saveDirName;
            recordLog(saveDir, fileName, msg, isContinueWrite);
        } catch (Exception e) {
            LogUtil.trace(Log.ERROR, "LogUtil: ", e.getMessage());
        }
    }

    /**
     * Write log
     *
     * @param logDir
     *            Log path to save
     * @param fileName
     * @param msg
     *            Log content
     * @param bool
     *            Save as type, false override save, true before file add save
     */
    private static void recordLog(String logDir, String fileName, String msg,
                                  boolean bool) {
        try {
            createDir(logDir);
            final File saveFile = new File(new StringBuffer().append(logDir)
                    .append("/").append(fileName).toString());
            if (!bool && saveFile.exists()) {
                saveFile.delete();
                saveFile.createNewFile();
                final FileOutputStream fos = new FileOutputStream(saveFile,
                        bool);
                fos.write(msg.getBytes());
                fos.close();
            } else if (bool && saveFile.exists()) {
                final FileOutputStream fos = new FileOutputStream(saveFile,
                        bool);
                fos.write(msg.getBytes());
                fos.close();
            } else if (bool && !saveFile.exists()) {
                saveFile.createNewFile();
                final FileOutputStream fos = new FileOutputStream(saveFile,
                        bool);
                fos.write(msg.getBytes());
                fos.close();
            } else if (!bool && !saveFile.exists()) {
                saveFile.createNewFile();
                final FileOutputStream fos = new FileOutputStream(saveFile,
                        bool);
                fos.write(msg.getBytes());
                fos.close();
            }
        } catch (IOException e) {
            recordLog(logDir, fileName, msg, bool);
        }
    }

    public static GlobalExceptionHandler processGlobalException(
            Application application, boolean isWriteIntoFile) {
        if (application != null) {
            GlobalExceptionHandler handler = new GlobalExceptionHandler(
                    application, isWriteIntoFile);
            Thread.setDefaultUncaughtExceptionHandler(handler);
            return handler;
        }
        return null;
    }

    private static String getDateformat(String pattern) {
        final DateFormat format = new SimpleDateFormat(pattern);
        return format.format(new Date());
    }

    private static File createDir(String dir) {
        final File file = new File(dir);
        if (!file.exists()) {
            file.mkdirs();
        }
        return file;
    }

}

